package com.dk.hi.core;

import java.util.ArrayList;
import java.util.List;

import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Polygon;
import org.newdawn.slick.tiled.TiledMap;

import com.dk.hi.gui.MapActor;

/**
 * Represents the map with blocking entities
 */
public class BlockMap {
	/**
	 * The screen x coordinate of the top left corner of the map
	 */
	private int x;

	/**
	 * The screen y coordinate of the top left corner of the map
	 */
	private int y;

	/**
	 * The tiled map
	 */
	private TiledMap map;

	/**
	 * The map width
	 */
	private int mapWidth;

	/**
	 * The map height
	 */
	private int mapHeight;

	/**
	 * All collision entities of the map (scenery)
	 */
	private List<Block> entities;

	/**
	 * Create a BlockMap
	 * 
	 * @param mapRef
	 *            - The path to the tiledMap
	 * @throws SlickException
	 */
	public BlockMap(String mapRef) throws SlickException {
		this.entities = new ArrayList<Block>();

		// Build the tiled map
		this.map = new TiledMap(mapRef);
		setMapWidth(this.map.getWidth() * this.map.getTileWidth());
		setMapHeight(this.map.getHeight() * this.map.getTileHeight());

		// For each blocking tile, we create a block
		for (int x = 0; x < this.map.getWidth(); x++) {
			for (int y = 0; y < this.map.getHeight(); y++) {
				int tileID = this.map.getTileId(x, y, 0);
				// The tile ID 1 is the unaccessible flag
				if (tileID == 1) {
					this.entities.add(new Block(x * 32, y * 32));
				}
			}
		}

		// We have to create blocks all around the map to prevent the player
		// from moving outside

		// Top border
		Polygon top = new Polygon(new float[] { 0, -32, this.mapWidth, -32, this.mapWidth, 0, 0, 0 });
		this.entities.add(new Block(top));

		// Bottom border
		Polygon bottom = new Polygon(new float[] { 0, this.mapHeight, this.mapWidth, this.mapHeight, this.mapWidth, this.mapHeight + 32, 0, this.mapHeight + 32 });
		this.entities.add(new Block(bottom));

		// Left border
		Polygon left = new Polygon(new float[] { -32, 0, 0, 0, 0, this.mapHeight, -32, this.mapHeight });
		this.entities.add(new Block(left));

		// Right border
		Polygon right = new Polygon(new float[] { this.mapWidth, 0, this.mapWidth + 32, 0, this.mapWidth + 32, this.mapHeight, this.mapWidth, this.mapHeight });
		this.entities.add(new Block(right));

	}

	public boolean collide(MapActor actor) {
		for (Block entity : this.entities) {
			if (actor.collide(entity)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * @return the map height
	 */
	public int getMapHeight() {
		return this.mapHeight;
	}

	/**
	 * @return the map width
	 */
	public int getMapWidth() {
		return this.mapWidth;
	}

	/**
	 * @return the map X coordinate on the screen
	 */
	public int getX() {
		return this.x;
	}

	/**
	 * @return the map Y coordinate on the screen
	 */
	public int getY() {
		return this.y;
	}

	/**
	 * Moves the map origin and all linked scenery blocks
	 * 
	 * @param dx
	 *            - x delta
	 * @param dy
	 *            - y delta
	 */
	public void moveOrigin(float dx, float dy) {
		this.x += dx;
		this.y += dy;
		for (Block tile : this.entities) {
			tile.moveBlock(dx, dy);
		}
	}

	/**
	 * Renders the map
	 * 
	 * @param g
	 *            - the canvas
	 */
	public void render(Graphics g) {
		this.map.render(this.x, this.y);

		// For debug
		if (Settings.DEBUG_ENTITIES) {
			for (Block block : this.entities) {
				block.draw(g);
			}
		}
	}

	/**
	 * Initializes the map height
	 * 
	 * @param mapWidth
	 *            - the map height
	 */
	protected void setMapHeight(int mapHeight) {
		this.mapHeight = mapHeight;
	}

	/**
	 * Initializes the map width
	 * 
	 * @param mapWidth
	 *            - the map width
	 */
	protected void setMapWidth(int mapWidth) {
		this.mapWidth = mapWidth;
	}

	/**
	 * Initializes the map origin. Use carefully!
	 * 
	 * @param x
	 *            - x coordinate
	 * @param y
	 *            - y coordinate
	 */
	public void setOrigin(int x, int y) {
		this.x = x;
		this.y = y;
		for (Block tile : this.entities) {
			tile.setBlockOrigin(x, y);
		}
	}
}
